package com.log4jviewer.domain;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.junit.BeforeClass;
import org.junit.Test;

import com.log4jviewer.filters.FilterItemModel;
import com.log4jviewer.filters.FilterModel;
import com.log4jviewer.filters.LogFilterEngine;

public class LogListTest {

    private static List<LogEvent> logMocks;

    @BeforeClass
    public static void init() {
        logMocks = new ArrayList<LogEvent>();
        logMocks.add(createLogMock("DEBUG", "DetClient", "Chinese is supported", "67", "13:52:58:371", "NDC 1",
                "Exception 1"));
        logMocks.add(createLogMock("DEBUG", "DetClient", "Japanese is supported", "23", "13:52:58:372", "NDC 2",
                "Exception 2"));
        logMocks.add(createLogMock("INFO", "DetServer$1", "Refreshing com.revere.det.app.DetServer$1@650646", "87",
                "13:52:58:429", "NDC 3", "Exception 3"));
        logMocks.add(createLogMock("DEBUG", "CollectionFactory", "Creating [java.util.concurrent.ConcurrentHashMap]",
                "27", "13:52:58:461", "NDC 4", "Exception 4"));
        logMocks.add(createLogMock("INFO", "XmlBeanDefinitionReader",
                "Loading XML bean definitions from class path resource", "57", "13:52:58:490", "NDC 5", "Exception 5"));
        logMocks.add(createLogMock("DEBUG", "DefaultDocumentLoader", "Using JAXP provider", "196", "13:52:58:506",
                "NDC 6", "Exception 6"));
    }

    private static LogEvent createLogMock(final String level, final String category, final String message,
            final String line, final String date, final String ndc, final String throwable) {
        LogEvent logMock = mock(LogEvent.class);
        when(logMock.getLevel()).thenReturn(level);
        when(logMock.getCategoryName()).thenReturn(category);
        when(logMock.getMessage()).thenReturn(message);
        when(logMock.getLineNumber()).thenReturn(line);
        when(logMock.getDate()).thenReturn(date);
        when(logMock.getNdc()).thenReturn(ndc);
        when(logMock.getThrowableInfo()).thenReturn(throwable);
        return logMock;
    }

    private static FilterModel createFilterMock() {
        FilterItemModel filterItemMock = mock(FilterItemModel.class);
        when(filterItemMock.getLogicOperand()).thenReturn(FilterItemModel.LogicOperand.AND);
        when(filterItemMock.getFieldType()).thenReturn(FilterItemModel.FieldType.LEVEL);
        when(filterItemMock.isInclude()).thenReturn(true);
        when(filterItemMock.getPattern()).thenReturn("INFO");
        when(filterItemMock.isEnabled()).thenReturn(true);

        FilterModel filterModel = new FilterModel();
        filterModel.addItem(filterItemMock);
        return filterModel;
    }

    @Test
    public void addLogTest() {
        int logBufferSize = 6;
        LogFilterEngine logFilterEngine = new LogFilterEngine();
        LogList logList = new LogList(logFilterEngine, logBufferSize);

        for (LogEvent log : logMocks) {
            logList.addLog(log);
        }

        Assert.assertEquals(logMocks.size(), logList.getFilteredLogsNum());
        Assert.assertEquals(logMocks.get(0), logList.getFilteredLog(0));
        Assert.assertEquals(logMocks.get(1), logList.getFilteredLog(1));
        Assert.assertEquals(logMocks.get(2), logList.getFilteredLog(2));
        Assert.assertEquals(logMocks.get(3), logList.getFilteredLog(3));
        Assert.assertEquals(logMocks.get(4), logList.getFilteredLog(4));
        Assert.assertEquals(logMocks.get(5), logList.getFilteredLog(5));
    }

    @Test
    public void addLogWithFilterTest() {
        FilterModel filterModel = createFilterMock();
        LogFilterEngine logFilterEngine = new LogFilterEngine();
        logFilterEngine.setFilter(filterModel);
        int logBufferSize = 6;
        LogList logList = new LogList(logFilterEngine, logBufferSize);

        for (LogEvent log : logMocks) {
            logList.addLog(log);
        }

        Assert.assertEquals(2, logList.getFilteredLogsNum());
        Assert.assertEquals(logMocks.get(2), logList.getFilteredLog(0));
        Assert.assertEquals(logMocks.get(4), logList.getFilteredLog(1));
    }

    @Test
    public void logBufferValidatorTest() {
        FilterModel filterModel = createFilterMock();
        LogFilterEngine logFilterEngine = new LogFilterEngine();
        logFilterEngine.setFilter(filterModel);
        int logBufferSize = 1;
        LogList logList = new LogList(logFilterEngine, logBufferSize);

        for (LogEvent log : logMocks) {
            logList.addLog(log);
        }
        Assert.assertEquals(0, logList.getFilteredLogsNum());

        logFilterEngine.setFilter(null);
        logList.revalidate();
        Assert.assertEquals(1, logList.getFilteredLogsNum());
        Assert.assertEquals(logMocks.get(5), logList.getFilteredLog(0));

        logList.clear();
        Assert.assertEquals(0, logList.getFilteredLogsNum());
        logList.updateLogBufferSize(5);

        for (LogEvent log : logMocks) {
            logList.addLog(log);
        }

        Assert.assertEquals(5, logList.getFilteredLogsNum());
        Assert.assertEquals(logMocks.get(1), logList.getFilteredLog(0));
        Assert.assertEquals(logMocks.get(2), logList.getFilteredLog(1));
        Assert.assertEquals(logMocks.get(3), logList.getFilteredLog(2));
        Assert.assertEquals(logMocks.get(4), logList.getFilteredLog(3));
        Assert.assertEquals(logMocks.get(5), logList.getFilteredLog(4));
    }
}
